/*
 * RTSAI - Real-Time Strategy engine for AI research
 * Copyright(C) 2006 DIMAp-UFRN, licensed under LGPL
 *
 * Game implementation
 */

#include <iostream>
#include <ctime>

#include "Game.h"
#include "CppLua.h"
#include "GameEvent.h"
#include "Log.h"


// singleton instance initialization (calls the default constuctor)
Game* Game :: instance = NULL;


/*! Default constructor. Initialize internal attributes. */
Game :: Game() : players ( Pool < Player > (2) ), running (false), paused (false) {
    clock.setPausedState ( true );
}


/*! Initialize the application named by file
 *  @param file Lua script file that contains the description of the application
 */
void Game :: init ( const char *file ) const
{
    // LOG_DEBUG << "Initializating game file <" << file << ">" << std::endl;
    Lua::runfile ( file );
}

/*! Reset the game data, erasing all previous data
 */
void Game :: reset ()
{
    // clear previous information
    /*
    foreach ( player, players ) {
        (*player).reset();
    }
    objects.clear();
    */
    instance = new Game();

    // setup new data
    // TODO
}



/*! Update the application. For now, just call players update
 */
bool Game :: update ()
{
    if (!paused) {
        foreach ( pl, players )
            (*pl).update ( elapsed_time );

        check_events ();
        Lua::call_function( "game.loop_callback","i>", elapsed_time );
    }
    return paused;
}


/*! Check if a registered event happened. If so, all listeners is notified.
 *  The data generated by the event are passed to the listeners.
 */
void Game :: check_events()
{
    GameEvent *event;
    GameEventData *data;
    foreach ( ev, registered_events ) {
        event = *ev;
        data = event -> check();
        if ( data ) {
            event -> notify_listeners ( data );
        }
    }
}


/*! Returns the registered event correnponding to a given name
 *  @param name Name of the event that will be returned
 */
GameEvent* Game :: get_event ( const std::string &name )
{
    foreach ( ev, registered_events ) {
        if ( (*ev) -> get_name() == name ) {
            return (*ev);
        }
    }
    return 0;
}


/*! Register an event. A registered event will be check if it happened on
 *  each game loop iteration.
 *  @param event Event that will be registered
 */
void Game :: register_event ( GameEvent *event )
{
    registered_events.push_front ( event );
}


/*! Unregister an event
 *  @param event Event that will be unregistered
 */
void Game :: unregister_event ( GameEvent *event )
{
    registered_events.remove ( event );
}


/*! Returns player named by name
 *  @param name The name of the player that will be returned
 */
Player& Game :: get_player ( const string name )
{
    foreach ( pl, players )
    {
        if ( (*pl).get_name() == name )
            return (*pl);
    }
}


/*! Add an object
 *  @param obj Game object that will be added
 */
void Game :: add_obj ( GameObject *obj )
{
    objects.push_back ( obj );
}


/*! Remove an object
 *  @param obj Game object that will be removed
 */
void Game :: remove_obj ( GameObject *obj )
{
    // TODO to implement
}


/*! Returns object corresponding index
 *  @param i Index of the object that will be returned
 */
GameObject* Game :: get_obj ( int i )
{
    /*TODO try
    {
        return &objects[i];
    }
    catch ( IndexOutOfBoundsExcepetion e )
    {
    }*/
    return dynamic_cast < GameObject* > ( objects[i] );
}


/*! Returns the number of the objects of the game
 */
int Game :: get_num_objs ()
{
    return objects.size();
}


/*! Returns a list that contains all objects
 */
ObjectList* Game  :: get_objs()
{
    return &objects;
}
